package com.yxy.utils;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Map;

/**
 * author: yuxiaoyang
 */
public class HttpClientUtils {
  private static RequestConfig config = null;
  //只有下述数组中的异常httpclient才会重试请求
  private static String[] retryDueToExceptions = {"org.apache.http.conn.ConnectTimeoutException"};

  static {
    final int connectTimeout = 3000;
    final int connectionRequestTimeout = 3000;
    final int socketTimeout = 3000;
    config = RequestConfig.custom().setConnectTimeout(connectTimeout)
            .setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout).build();
  }

  public static String httpClientUpload(String url, MultipartFile file, Map<String, String> params)
          throws ClientProtocolException, IOException {
    //HttpClient httpclient = new DefaultHttpClient();//过时的方法
    HttpClient httpclient = HttpClientBuilder.create().build();
    // 请求处理页面
    HttpPost httppost = new HttpPost(url);
    // 创建待处理的文件
    String fileName = file.getOriginalFilename();
    ContentBody files = new ByteArrayBody(file.getBytes(), fileName);
    // 对请求的表单域进行填充
    MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
    multipartEntityBuilder.addPart("file", files);

    if (params != null) {//这里草草处理values[]
      for (String key : params.keySet()) {
        String value = params.get(key);
        try {
          value = URLEncoder.encode(value, "UTF-8");
          multipartEntityBuilder.addPart(key, new StringBody(value));
        } catch (UnsupportedEncodingException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }

      }
    }
    // 设置请求
    httppost.setEntity(multipartEntityBuilder.build());
    // 执行
    HttpResponse response = httpclient.execute(httppost);
    if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
      HttpEntity entity = response.getEntity();
      return EntityUtils.toString(entity, Charset.forName("UTF-8"));
    }
    return null;
  }

  /**
   * @param uri                      the request address
   * @param json                     the request data that must be a JSON string
   * @return null when method parameter is null, "", " "
   * @throws IOException    if HTTP connection can not opened or closed successfully
   * @throws ParseException if response data can not be parsed successfully
   */
  public static String postJson(String uri, String json){
    if (StringUtils.isAnyBlank(uri, json)) {
      return null;
    }

    CloseableHttpClient client = HttpClientBuilder.create()
            .setRetryHandler(new HttpRequestRetryHandler() {
              @Override
              public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                String exceptionName = exception.getClass().getName();
                //判断在不在重试异常列表中,不在则不再重试，直接退出
                if (!Arrays.asList(retryDueToExceptions).contains(exceptionName)) {
                  return false;
                }
                System.err.println("retry, cause----->" + exceptionName);
                if (executionCount >= 3) {//各种可恢复异常总共发生的次数
                  // Do not retry if over max retry count
                  return false;
                }
                return true;
              }
            }).build();
    HttpPost post = new HttpPost(uri);
    // Create request data
    StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
    // Set request body
    post.setEntity(entity);
    post.setConfig(config);
    // Response content
    String responseContent = null;
    CloseableHttpResponse response = null;
    try {
      response = client.execute(post);
      if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
        responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8.name());
      }
    } catch (IOException ex) {
      System.err.println("postJson failded, ex---->" + ex);//重试n次，这行只最后打印一次
      return null;
    } finally {
      if (ObjectUtils.anyNotNull(response)) {
        try {
          response.close();
        } catch (IOException e) {
        }
      }
      if (ObjectUtils.anyNotNull(client)) {
        try {
          client.close();
        } catch (IOException e) {

        }
      }
    }
    return responseContent;
  }

  public static String get(String uri){
    if (StringUtils.isAnyBlank(uri)) {
      return null;
    }

    CloseableHttpClient client = HttpClientBuilder.create()
            .setRetryHandler(new HttpRequestRetryHandler() {
              @Override
              public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                String exceptionName = exception.getClass().getName();
                //判断在不在重试异常列表中,不在则不再重试，直接退出
                if (!Arrays.asList(retryDueToExceptions).contains(exceptionName)) {
                  return false;
                }
                System.err.println("retry, cause----->" + exceptionName);
                if (executionCount >= 3) {//各种可恢复异常总共发生的次数
                  // Do not retry if over max retry count
                  return false;
                }
                return true;
              }
            }).build();
    HttpGet request = new HttpGet(uri);
    request.setConfig(config);
    // Response content
    String responseContent = null;
    CloseableHttpResponse response = null;
    try {
      response = client.execute(request);
      if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
        responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8.name());
      }
    } catch (IOException ex) {
      System.err.println("get request failded, ex---->" + ex);//重试n次，这行只最后打印一次
      return null;
    } finally {
      if (ObjectUtils.anyNotNull(response)) {
        try {
          response.close();
        } catch (IOException e) {
        }
      }
      if (ObjectUtils.anyNotNull(client)) {
        try {
          client.close();
        } catch (IOException e) {

        }
      }
    }
    return responseContent;
  }

  public static void main(String[] args) {
    //发生retry的异常有：org.apache.http.conn.ConnectTimeoutException
    //java.net.UnknownHostException
    //String url = "http://www.yuxiaoyang1111.com";//域名不存在异常，不会重试
    String url = "http://8.5.2.1"; //超时异常，会重试
    String jsonParams = "{\"a\": \"b\"}";
    HttpClientUtils.postJson(url, jsonParams);
  }
}
